package com.mask.token.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.Instant;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Token黑名单服务
 * 支持将Token加入黑名单，实现强制下线功能
 *
 * @author mask
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnClass(RedisTemplate.class)
public class MaskTokenBlacklistService {

    private final RedisTemplate<String, String> redisTemplate;

    /**
     * 黑名单Key前缀
     */
    private static final String BLACKLIST_PREFIX = "mask:token:blacklist:";

    /**
     * 将Token加入黑名单
     *
     * @param token Token字符串
     * @param reason 加入黑名单的原因
     * @param expireTime 黑名单过期时间
     */
    public void addToBlacklist(String token, String reason, Instant expireTime) {
        try {
            String blacklistKey = BLACKLIST_PREFIX + token;
            long expireSeconds = Duration.between(Instant.now(), expireTime).getSeconds();
            
            if (expireSeconds > 0) {
                redisTemplate.opsForValue().set(blacklistKey, reason, expireSeconds, TimeUnit.SECONDS);
                log.info("Token已加入黑名单: {}, 原因: {}, 过期时间: {}", token, reason, expireTime);
            }
        } catch (Exception e) {
            log.error("将Token加入黑名单失败", e);
        }
    }

    /**
     * 将Token加入黑名单（使用默认过期时间）
     *
     * @param token Token字符串
     * @param reason 加入黑名单的原因
     */
    public void addToBlacklist(String token, String reason) {
        // 默认黑名单有效期24小时
        addToBlacklist(token, reason, Instant.now().plus(Duration.ofHours(24)));
    }

    /**
     * 检查Token是否在黑名单中
     *
     * @param token Token字符串
     * @return 是否在黑名单中
     */
    public boolean isInBlacklist(String token) {
        try {
            String blacklistKey = BLACKLIST_PREFIX + token;
            return redisTemplate.hasKey(blacklistKey);
        } catch (Exception e) {
            log.error("检查Token黑名单状态失败", e);
            return false;
        }
    }

    /**
     * 获取Token黑名单原因
     *
     * @param token Token字符串
     * @return 黑名单原因
     */
    public String getBlacklistReason(String token) {
        try {
            String blacklistKey = BLACKLIST_PREFIX + token;
            return redisTemplate.opsForValue().get(blacklistKey);
        } catch (Exception e) {
            log.error("获取Token黑名单原因失败", e);
            return null;
        }
    }

    /**
     * 从黑名单中移除Token
     *
     * @param token Token字符串
     */
    public void removeFromBlacklist(String token) {
        try {
            String blacklistKey = BLACKLIST_PREFIX + token;
            redisTemplate.delete(blacklistKey);
            log.info("Token已从黑名单中移除: {}", token);
        } catch (Exception e) {
            log.error("从黑名单中移除Token失败", e);
        }
    }

    /**
     * 清理过期的黑名单Token
     */
    public void cleanExpiredBlacklist() {
        try {
            String pattern = BLACKLIST_PREFIX + "*";
            Set<String> blacklistKeys = redisTemplate.keys(pattern);
            
            if (blacklistKeys != null && !blacklistKeys.isEmpty()) {
                int cleanedCount = 0;
                for (String key : blacklistKeys) {
                    if (!redisTemplate.hasKey(key)) {
                        cleanedCount++;
                    }
                }
                log.info("清理了 {} 个过期黑名单Token", cleanedCount);
            }
        } catch (Exception e) {
            log.error("清理过期黑名单Token失败", e);
        }
    }

    /**
     * 获取黑名单Token数量
     *
     * @return 黑名单Token数量
     */
    public long getBlacklistCount() {
        try {
            String pattern = BLACKLIST_PREFIX + "*";
            Set<String> blacklistKeys = redisTemplate.keys(pattern);
            return blacklistKeys != null ? blacklistKeys.size() : 0;
        } catch (Exception e) {
            log.error("获取黑名单Token数量失败", e);
            return 0;
        }
    }

    /**
     * 获取所有黑名单Token
     *
     * @return 黑名单Token集合
     */
    public Set<String> getAllBlacklistTokens() {
        try {
            String pattern = BLACKLIST_PREFIX + "*";
            Set<String> blacklistKeys = redisTemplate.keys(pattern);
            
            if (blacklistKeys != null) {
                return blacklistKeys.stream()
                        .map(key -> key.substring(BLACKLIST_PREFIX.length()))
                        .collect(java.util.stream.Collectors.toSet());
            }
            
            return java.util.Collections.emptySet();
        } catch (Exception e) {
            log.error("获取所有黑名单Token失败", e);
            return java.util.Collections.emptySet();
        }
    }
}
